package xxl.robotlegs.framework.impl.lifecycle 
{
	/**
	 * ...
	 * @author XXL
	 */
	public class LifecycleTransition 
	{
		private const _fromStates:Vector.<String> = new Vector.<String>;
		private const _callbacks:Array = [];
		private const _signal:LifecycleSignal = new LifecycleSignal(this);
		private var _name:String;
		private var _lifecycle:Lifecycle;
		private var _transitionState:String;
		private var _finalState:String;
		private var _preTransitionEvent:String;
		private var _transitionEvent:String;
		private var _postTransitionEvent:String;
		private var _reverse:Boolean;
		
		public function LifecycleTransition(name:String, lifecycle:Lifecycle) 
		{
			_name = name;
			_lifecycle = lifecycle;
		}
		
		public function fromStates(...states):LifecycleTransition
		{
			const len:int = states.length;
			for (var i:int = 0; i < len; i++) 
			{
				_fromStates.push(states[i]);
			}
			return this;
		}
		
		public function toStates(transitionState:String, finalState:String):LifecycleTransition
		{
			_transitionState = transitionState;
			_finalState = finalState;
			return this;
		}
		
		public function withEvents(preTransitionEvent:String, transitionEvent:String, postTransitionEvent:String):LifecycleTransition
		{
			_preTransitionEvent = preTransitionEvent;
			_transitionEvent = transitionEvent;
			_postTransitionEvent = postTransitionEvent;
			return this;
		}
		
		public function addBeforeHandler(handler:Function):LifecycleTransition
		{
			_signal.addToMap(_name, handler);
			return this;
		}
		
		public function enter(callback:Function = null):void
		{
			const initialState:String = _lifecycle.state;
			if (initialState == _finalState)
			{
				callback && _signal.safelyCallBack(callback, _name, null);
				return;
			}
			if (initialState == _transitionState)
			{
				callback && _callbacks.push(callback);
				return;
			}
			if (invalidTransition())
			{
				reportError("无效的转换", [callback]);
				return;
			}
			callback && _callbacks.push(callback);
			setState(_transitionState);
			try
			{
				_signal.dispatchFun(_name);
			}
			catch (error:Error)
			{
				setState(initialState);
				reportError(error, _callbacks.concat());
				_callbacks.length = 0;
				return;
			}
			dispatch(_preTransitionEvent);
			dispatch(_transitionEvent);
			setState(_finalState);
			const callbacks:Array = _callbacks.concat();
			_callbacks.length = 0;
			const len:int = callbacks.length;
			for (var i:int = 0; i < len; i++) 
			{
				_signal.safelyCallBack(callbacks[i], _name, null);
			}
			dispatch(_postTransitionEvent);
		}
		
		//----------private
		
		private function invalidTransition():Boolean 
		{
			return _fromStates.length > 0
				&& _fromStates.indexOf(_lifecycle.state) == -1;
		}
		
		private function reportError(message:Object, callbacks:Array = null):void
		{
			const error:LifecycleError = message is LifecycleError
				? message as LifecycleError
				: new LifecycleError(message.toString());
			
			if (_lifecycle.signal.getNumListenersByKey(LifecycleSignal.ERROR) > 0)
			{
				_lifecycle.signal.dispatchFun(LifecycleSignal.ERROR, error);
				if (callbacks)
				{
					const len:int = callbacks.length;
					for (var i:int = 0; i < len; i++) 
					{
						var callback:Function = callbacks[i];
						callback && _signal.safelyCallBack(callback, _name, error);
					}
				}
			}
			else
			{
				throw error;
			}
		}
		
		private function setState(state:String):void
		{
			state && _lifecycle.setCurrentState(state);
		}
		
		private function dispatch(type:String):void
		{
			if (type)
			{
				_lifecycle.signal.dispatchFun(type);
			}
		}
	}

}